<template>
  <div class="toolbar">
    <i class="toolbar-icon" title="插入表情" ref="triggerEle">
      <SvgIcon icon-class="smile" popper-class="icon" />
    </i>
    <i class="toolbar-icon" title="拍照" @click="startVideo">
      <SvgIcon icon-class="cameratwo" popper-class="icon" />
    </i>
    <el-popover
      :virtual-ref="$refs.triggerEle"
      trigger="hover"
      :placement="placement"
      :width="220"
      virtual-triggering
    >
      <el-scrollbar :height="170">
        <ul>
          <li
            class="toolbar-smile__item"
            v-for="[emotion, { id, url }] in emotionsData"
            :key="id"
          >
            <img
              draggable="false"
              :title="emotion"
              :src="`https://face.t.sinajs.cn/t4/appstyle/expression/ext/normal/${url}`"
              :alt="emotion"
              @click="startInsert(emotion)"
            />
          </li></ul
      ></el-scrollbar>
    </el-popover>
  </div>
  <template v-if="showVideo"
    ><teleport to="body">
      <div class="photo-video">
        <video ref="videoRef"></video>
        <div class="photo-video__toolbar">
          <i title="取消" class="photo-video__toolbar--icon" @click="closeVideo">
            <SvgIcon icon-class="close" popper-class="icon" />
          </i>
          <i title="确定" class="photo-video__toolbar--icon" @click="confirmVideo">
            <SvgIcon icon-class="check" popper-class="icon" />
          </i>
        </div>
      </div> </teleport
  ></template>
</template>

<script lang="ts" setup>
import { ref, nextTick } from "vue";
import emotionsData from "@/staticDatas/emotion";
import insertEmotion from "@/plugins/insertEmotion";
import { ElMessage } from "element-plus";
import { compress } from "image-conversion";
import { dataURItoBlob, blobToBase64 } from "@/plugins/pictureProcess";

const props = withDefaults(
  defineProps<{
    textareaEle: HTMLTextAreaElement;
    disabled?: boolean;
    placement?: "right" | "bottom";
    count?: number;
  }>(),
  {
    disabled: false,
    placement: "right",
  }
);

const emits = defineEmits<{
  (e: "updateContent", payload: { isModify: boolean; content?: string }): void;
  // 拍照上传图片
  (e: "change", url: string[]): any;
}>();

// 准备插入表情
const startInsert = (emotion: string) =>
  !props.disabled &&
  emits(
    "updateContent",
    insertEmotion({ el: props.textareaEle, emotion, count: props.count })
  );

/**
 * 是否调用摄像头显示录像
 */
const showVideo = ref<boolean>(false);
/**
 * 给video元素一个ref属性
 */
const videoRef = ref<HTMLVideoElement>();
/**
 * 视频流
 */
let videoStream: MediaStream;
/**
 * 是否正在打开摄像头
 */
const isOpen = ref<boolean>(false);

// 打开摄像头开始拍照
const startVideo = async () => {
  if (!isOpen.value) {
    isOpen.value = true;
    try {
      videoStream = await navigator.mediaDevices.getUserMedia({
        video: {
          width: globalThis.innerWidth,
          height: globalThis.innerHeight,
        },
      });
      showVideo.value = true;
      nextTick(() => {
        videoRef.value!.srcObject = videoStream;
        videoRef.value!.onloadedmetadata = async () => await videoRef.value?.play();
      });
      isOpen.value = false;
    } catch (error) {
      console.log(error);
      ElMessage({
        message: "请先打开摄像头权限",
        type: "error",
        duration: 1500,
      });
      isOpen.value = false;
    }
  }
};

// 压缩图片
const compressImg = (file: Blob) => {
  return new Promise<string>(async (resolve) => {
    let blob: Blob = file;
    // 如果图片大于0.5MB的话则压缩图片
    if (blob.size / 1024 / 1024 > 0.5) blob = await compress(blob, 0.25);
    blobToBase64(blob, (url: string) => resolve(url));
  });
};

// 点击确定按钮开始拍照
const confirmVideo = () => {
  const canvas: HTMLCanvasElement = document.createElement("canvas");
  canvas.width = globalThis.innerWidth;
  canvas.height = globalThis.innerHeight;
  canvas.getContext("2d")?.drawImage(videoRef.value!, 0, 0, canvas.width, canvas.height);
  const src: string = canvas.toDataURL();
  compressImg(dataURItoBlob(src)).then((url) => {
    emits("change", [url]);
    closeVideo();
  });
};

// 关闭摄像头
const closeVideo = () => {
  videoStream.getTracks().forEach((track) => track.stop());
  showVideo.value = false;
};
</script>

<style lang="scss" scoped>
.toolbar {
  margin-top: 15px;
  height: 22px;

  &-icon {
    display: inline-block;
    height: 22px;
    font-size: 22px;
    cursor: pointer;
    margin-right: 12px;

    .icon {
      vertical-align: super;
      color: rgba(130, 129, 129, 0.8470588235);
    }
  }

  &-smile {
    &__item {
      display: inline-block;
      margin: 4px 5px;

      img {
        @include setWidHei(20px, 20px);
        cursor: pointer;
      }
    }
  }
}

.photo-video {
  position: absolute;
  inset: 0;
  z-index: 9999;

  video {
    @include setWidHei(100%, 100%);
  }

  &__toolbar {
    @include setWidHei(50px, 150px);
    position: absolute;
    top: 50%;
    right: 5%;
    transform: translateY(-50%);

    &--icon {
      &:first-child {
        margin-bottom: 50px;
      }

      position: relative;
      display: inline-block;
      @include setWidHei(50px, 50px);
      background-color: #fff;
      border-radius: 50%;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;

      .icon {
        color: #333;
        font-size: 30px;
        opacity: 0.8;
        transition: opacity 0.25s;
      }

      &:hover {
        .icon {
          opacity: 1;
        }
      }
    }
  }
}
</style>
